#include "TcpServer.h"
#include "Logger.h"
#include <functional>
#include <strings.h>
#include "TcpConnection.h"

static EventLoop* CheckLoopNotNull(EventLoop *loop) {
    if (loop == nullptr) {
        LOG_FATAL("mainloop is nullptr\n");
    }
    return loop;
}

TcpServer::TcpServer(EventLoop *loop, 
                const InetAddress& listenAddr,
                const std::string& nameArg,
                Option option)
    : loop_(CheckLoopNotNull(loop))
    , ipPort_(listenAddr.toIpPort())
    , name_(nameArg)
    , acceptor_(new Acceptor(loop, listenAddr, option == kReusePort))
    , threadPool_(new EventLoopThreadPool(loop, name_))
    , connectionCallback_()
    , messageCallback_()
    , nextConnId_(1)
{
    // 当有新用户连接时， 会执行这个回调
    acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, 
            this, std::placeholders::_1, std::placeholders::_2));
}


TcpServer::~TcpServer()
{
    //释放资源
    for (auto&item : connections_)
    {
        TcpConnectionPtr conn(item.second);
        item.second.reset();//释放智能指针指向的资源
        conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestroyed,conn));
    }
}

void TcpServer::removeConnection(const TcpConnection &conn)
{
    loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}

///有一个新客户端连接会执行这个回调
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) {
    // 轮询算法 选择一个subLoop 来管理channel
    EventLoop *ioLoop = threadPool_->getNextLoop();
    char buf[64];
    snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);
    nextConnId_++;
    std::string connName = name_ + buf;
    // 打个日志
    LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s \n", 
                    name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());

    
    //通过sockfd获取服务器的ip port
    sockaddr_in local;
    ::bzero(&local, sizeof local);
    socklen_t addrlen = sizeof local; 
    if (::getsockname(sockfd, (sockaddr*)&local, &addrlen) < 0) {
        LOG_ERROR("::getsockname error\n");
    }
    InetAddress localAddr(local);

    // 根据连接成功的sockfd创建tcpConnectionPtr
    TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));
    connections_[connName] = conn;

    //TcpServer => TcpConnection => Channel => Poller => Channel
    conn->setConnectionCallback(connectionCallback_);
    conn->setMessageCallback(messageCallback_);
    conn->setWriteCompleteCallback(writeCompleteCallback_);

    conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));

    // 直接调用TcpConnection::connectEstablished
    ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
 
}

void TcpServer::start()//开启服务器监听，
{
    if (started_++ == 0) {//防止一个TcpServer对象被start多次
        threadPool_->start(threadInitCallback_); // 启动loop线程池
        loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));
    }
}

void TcpServer::setThreadNum(int numThreads) {
    threadPool_->setThreadNum(numThreads);
}



void TcpServer::removeConnectionInLoop(const TcpConnection& conn)
{
    LOG_INFO("TcpServer::removeConnectionInLoop [%s] - [%s]\n", name_.c_str(), conn.name().c_str());
    connections_.erase(conn.name());
    EventLoop *ioLoop = conn.getLoop();
    ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}